var gulp            = require('gulp'),
    plumber         = require('gulp-plumber'),
    uglify          = require('gulp-uglify'),
    sass            = require('gulp-sass'),
    rename          = require('gulp-rename'),
    rev             = require('gulp-rev'),
    htmlmin         = require('gulp-minify-html'),
    es              = require('event-stream'),
    parse           = require('esprima').parse,
    toString        = require('escodegen').generate,
    confusion       = require('confusion'),
    concat          = require('gulp-concat'),
    fs              = require('fs'),
    runSequence     = require('run-sequence'),
    gulpif          = require('gulp-if'),
    clean           = require('gulp-clean'),
    revCollector    = require('gulp-rev-collector'),

    // requireJS 打包
    // requireJS    = require('requirejs'),// 失败了；
    amdOptimize     = require('amd-optimize'),

    SceneVariable   = process.env.GULP_ENV || 'development',
    asset = {
        js: './asset/js/**/*.js',
        scss: './asset/scss/**/*.scss',
        font: './asset/font/**/*',
        image: './asset/image/**/*',
        component: './asset/component/**/*',

        // 页面压缩
        template: {
            frontend: './application/index/view/before/**/*.html',
            backend: './application/backend/view/before/**/*.html'
        }
    },
    bundle = {
        env: {
            dev: 'development',
            pro: 'production'
        },
        revision: process.env.REV_ENV || false,
        asset: {
            js: './public/static/js',
            css: './public/static/css',
            font: './public/static/font',
            image: './public/static/image',
            component: './public/static/component',
            template: {
                frontend: './application/index/view/after',
                backend: './application/backend/view/after'
            }
        },

        revPath: './public/static/rev'
    };

var confusionGulp = function () {
    return es.map(function (file, callback) {
        // console.log(file);
        if (file.isNull()) {
            return callback(null, file);
        }
        var ast = parse(fs.readFileSync(file.path));
        var obfuscated = confusion.transformAst(ast, confusion.createVariableName);
        file.contents = new Buffer(toString(obfuscated));
        return callback(null, file);
    });
}

// 公用组件
/*
gulp.task('component', function() {
    if (SceneVariable == bundle.env.dev) {
        gulp.src(asset.componentHtml)
            .pipe(gulp.dest('./public/component'));
        gulp.src(asset.componentJs)
            .pipe(gulp.dest('./public/component'));
        gulp.src(asset.componentCss)
            .pipe(gulp.dest('./public/component'));
        gulp.src(asset.componentScss)
            .pipe(plumber())
            .pipe(scss({outputStyle: 'compressed'}))
            .pipe(gulp.dest('./public/component'));
    } else {
        gulp.src(asset.componentHtml)
            .pipe(rev())
            .pipe(gulp.dest('./public/component'))
            .pipe(rev.manifest())
            .pipe(gulp.dest(asset.revPath + '/component/html'));
        gulp.src(asset.componentJs)
            .pipe(uglify({
                mangle: true,
                output: {
                    beautify: true
                },
                compress: true
            }))
            .pipe(confusionGulp())
            .pipe(uglify())
            .pipe(rev())
            .pipe(gulp.dest('./public/component'))
            .pipe(rev.manifest())
            .pipe(gulp.dest(asset.revPath + '/component/js'));
        gulp.src(asset.componentCss)
            .pipe(rev())
            .pipe(gulp.dest('./public/component'))
            .pipe(rev.manifest())
            .pipe(gulp.dest(asset.revPath + '/component/css'));
        gulp.src(asset.componentScss)
            .pipe(plumber())
            .pipe(scss({outputStyle: 'compressed'}))
            .pipe(rev())
            .pipe(gulp.dest('./public/component'))
            .pipe(rev.manifest())
            .pipe(gulp.dest(asset.revPath + '/component/scss'));
    }
});
*/

// 图片
gulp.task('image', function() {
    if (SceneVariable == bundle.env.dev) {
        gulp.src(asset.image).pipe(gulp.dest(bundle.asset.image));
    } else {
        // gulp.src(asset.image)
            // .pipe(rev())
            // .pipe(gulp.dest(bundle.asset.image));
            // .pipe(rev.manifest())
            // .pipe(gulp.dest(asset.revPath+'/image'));
        
        if (bundle.revision) {
            gulp.src(asset.image).pipe(rev()).pipe(gulp.dest(bundle.asset.image))
                .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/image'));
        } else {
            gulp.src(asset.image).pipe(gulp.dest(bundle.asset.image));
        }
    }
});
gulp.task('clean-image', function () {
    return gulp.src(['./public/static/image'], {read: false}).pipe(clean());
});

// 字体文件
gulp.task('font', function () {
    if (SceneVariable == bundle.env.dev) {
        gulp.src(asset.font).pipe(gulp.dest(bundle.asset.font))
    } else {
        // gulp.src(asset.font)
            // .pipe(rev())
            // .pipe(gulp.dest(bundle.asset.font));
            // .pipe(rev.manifest())// 生成版本号地图
            // .pipe(gulp.dest(asset.revPath + '/font'));
        
        if (bundle.revision) {
            gulp.src(asset.font).pipe(rev()).pipe(gulp.dest(bundle.asset.font))
                .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/font'));
        } else {
            gulp.src(asset.font).pipe(gulp.dest(bundle.asset.font));
        }
    }
});
gulp.task('clean-font', function () {
    return gulp.src(['./public/static/font'], {read: false}).pipe(clean());
});

// scss
gulp.task('scss', function () {
    if (SceneVariable == bundle.env.dev) {
        // gulp.src(asset.css).pipe(gulp.dest(bundle.asset.css));
        
        // gulp.src(asset.scss)
        //     .pipe(plumber())
        //     .pipe(sass({
        //         outputStyle: 'expanded'
        //     }))
        //     .pipe(gulp.dest(bundle.asset.css));
        
        // expanded 或者 nested；

        // 合并 css；
        gulp.src([
            './asset/scss/app.scss',
            './asset/scss/page/**/*.scss'
        ])
            .pipe(concat('app.scss'))
            .pipe(plumber())
            .pipe(sass({
                outputStyle: 'expanded'
            }))
            .pipe(gulp.dest(bundle.asset.css));

        gulp.src([
            asset.scss,
            '!./asset/scss/page/**/*.scss',
            '!./asset/scss/app.scss',
        ])
            .pipe(plumber())
            .pipe(sass({
                outputStyle: 'expanded'
            }))
            .pipe(gulp.dest(bundle.asset.css));
    } else {
        // gulp.src(asset.scss)
            // .pipe(plumber())
            // .pipe(scss({outputStyle: 'compressed'}))
            // .pipe(rev())
            // .pipe(gulp.dest(bundle.asset.css));
            // .pipe(rev.manifest())
            // .pipe(gulp.dest(asset.revPath + '/css'));
        
        if (bundle.revision) {
            // gulp.src(asset.css).pipe(rev()).pipe(gulp.dest(bundle.asset.css))
            //     .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/css'));
            
            // compact 或者 compressed；
            // gulp.src(asset.scss).pipe(plumber()).pipe(sass({outputStyle: 'compact'})).pipe(rev()).pipe(gulp.dest(bundle.asset.css))
                // .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/css'));

            // 经过测试，对于 rev.manifest() 产生的清单文件，同一个文件时，后面的会覆盖前面的；
            // 所以不能使用这种方式；暂时找不到追加的方法，就只能简单点另起文件名了。

            gulp.src([
                './asset/scss/app.scss',
                './asset/scss/page/**/*.scss'
            ])
                .pipe(concat('app.scss'))
                .pipe(plumber())
                .pipe(sass({outputStyle: 'compact'}))
                .pipe(rev())
                .pipe(gulp.dest(bundle.asset.css))
                .pipe(rev.manifest())
                .pipe(gulp.dest(bundle.revPath + '/css'));

            gulp.src([
                asset.scss,
                '!./asset/scss/page/**/*.scss',
                '!./asset/scss/app.scss',
            ])
                .pipe(plumber())
                .pipe(sass({outputStyle: 'compact'}))
                .pipe(rev())
                .pipe(gulp.dest(bundle.asset.css))
                .pipe(rev.manifest())
                .pipe(gulp.dest(bundle.revPath + '/css2'));
            
        } else {
            // gulp.src(asset.css).pipe(gulp.dest(bundle.asset.css));
            // gulp.src(asset.scss).pipe(plumber()).pipe(sass({outputStyle: 'compressed'})).pipe(gulp.dest(bundle.asset.css));
            
            gulp.src(asset.scss).pipe(plumber()).pipe(sass({outputStyle: 'compressed'})).pipe(gulp.dest(bundle.asset.css));
        }
    }
});
gulp.task('clean-scss', function () {
    return gulp.src(['./public/static/css'], {read: false}).pipe(clean());
});

// 压缩js
gulp.task('js', function(cb) {
    if (SceneVariable == bundle.env.dev) {
        // gulp.src([asset.js]).pipe(gulp.dest(bundle.asset.js));// 并没有压缩

        // 处理requireJS 部分；不知道怎么用，失败了。
        // requireJS.optimize({
        //     baseUrl: "./asset/js",
        //     mainConfigFile: "./asset/js/main.js",
        //     out: './public/static/js/req.js',
        //     // include: false,
        //     //去掉头部版权声明
        //     preserveLicenseComments: false,
        //     //自动删除被合并过的文件
        //     removeCombined: false, 
        // }, function (buildResponse) {
        //     console.log('build response', buildResponse);
        //     cb();
        // }, cb)

        // 打包 requireJS 的另一种方式
        gulp.src('./asset/js/**/*.js')
            .pipe(amdOptimize('require-entry', {
              // configFile: './js/require-config.js',
              findNestedDependencies: true,
              include: false
            }))
            .pipe(concat('require-entry.js'))
            // .pipe(uglifyJS('test.js'))
            .pipe(gulp.dest('./public/static/js'));

        // 合并 js；
        gulp.src([
            './asset/js/app.js',
            './asset/js/page/**/*.js'
        ])
            .pipe(concat('app.js'))
            .pipe(gulp.dest(bundle.asset.js));// 并没有压缩

        gulp.src([
            asset.js,
            // 因为计划把下面这些js 合并；
            '!./asset/js/page/**/*.js',
            '!./asset/js/app.js',
            '!./asset/js/main.js',
            '!./asset/js/module/**/*.js'
        ])
            .pipe(gulp.dest(bundle.asset.js));// 并没有压缩
    } else {
        /*
            gulp.src([asset.js])
                .pipe(uglify({
                    mangle: true,
                    output: {
                        beautify: true
                    },
                    compress: true
                }))
                .pipe(confusionGulp())
                .pipe(uglify())
                .pipe(rev())                                    // 生成相关版本号
                .pipe(gulp.dest('./public/js'))                 // 压缩之后的js文件输出目录
                .pipe(rev.manifest())                           // 生成版本号地图
                .pipe(gulp.dest(asset.revPath + '/js'));        // 输出地图文件目录
            gulp.src(['./asset/js/base/config-' + SceneVariable + '.js'])
                .pipe(uglify({
                    mangle: true,
                    output: {
                        beautify: true
                    },
                    compress: true
                }))
                .pipe(confusionGulp())
                .pipe(rename('config-static-wap.js'))
                .pipe(uglify())
                .pipe(rev())                                    // 生成相关版本号
                .pipe(gulp.dest('./public/js/base'))            // 压缩之后的js文件输出目录
                .pipe(rev.manifest())                           // 生成版本号地图
                .pipe(gulp.dest(asset.revPath + '/js/base'));   // 输出地图文件目录
        */

        if (bundle.revision) {
            // gulp.src([asset.js])
            //     .pipe(uglify({
            //         mangle: true,
            //         output: {
            //             beautify: true
            //         },
            //         compress: true
            //     }))
            //     .pipe(confusionGulp())
            //     .pipe(uglify())
            //     .pipe(rev())
            //     .pipe(gulp.dest(bundle.asset.js))
            //     .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/js'));

            // 处理requireJS 部分；
            // requireJS.optimize({
            //     baseUrl: "./asset/js",
            //     mainConfigFile: "main.js",
            //     preserveLicenseComments: false,
            //     //去掉头部版权声明
            //     removeCombined: false, 
            //     //自动删除被合并过的文件
            // }, function (buildResponse) {
            //     // console.log('build response', buildResponse);
            //     cb();
            // }, cb)
            
            // 打包 requireJS 的另一种方式
            gulp.src('./asset/js/**/*.js')
                .pipe(amdOptimize('require-entry', {
                  // configFile: './js/require-config.js',
                  findNestedDependencies: true,
                  include: false
                }))
                .pipe(concat('require-entry.js'))
                // .pipe(uglifyJS('test.js'))
                .pipe(gulp.dest('./public/static/js'));

            gulp.src([
                './asset/js/app.js',
                './asset/js/page/**/*.js'
            ])
                // 压缩，对每个源文件，也就是在合并之间的；
                // 这说明合并后，各个文件的内容必然不在同一行；
                .pipe(uglify({
                    // 看不出变化；
                    mangle: true,
                    output: {
                        // true，表示进行格式化；
                        // false，表示压缩，一个文件的内容在单独一行；
                        beautify: false
                    },
                    // 目前看到的变化是，源码中两个console.log 之间用的分号，这里使用true 后，变成了逗号；
                    // 但也不是说分号都会变成逗号。
                    compress: false
                }))
                // 混淆，变量名看不懂；
                // .pipe(confusionGulp())
                .pipe(concat('app.js'))
                // 这是对合并后的文件的；我的建议是不用这个，每个文件的单独一行蛮好的；
                // .pipe(uglify())
                .pipe(rev())
                .pipe(gulp.dest(bundle.asset.js))
                .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/js'));
            gulp.src([
                asset.js,
                // 因为计划把下面这些js 合并；
                '!./asset/js/app.js',
                '!./asset/js/page/**/*.js',
                // requireJS 打包了；
                '!./asset/js/require-entry.js',
                '!./asset/js/module/**/*.js'
            ])
                .pipe(uglify({
                    mangle: true,
                    output: {
                        beautify: true
                    },
                    compress: true
                }))
                // .pipe(confusionGulp())
                // .pipe(uglify())
                .pipe(rev())
                .pipe(gulp.dest(bundle.asset.js))
                .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/js2'));
        } else {
            // gulp.src([asset.js])
            //     .pipe(uglify({
            //         mangle: true,
            //         output: {
            //             beautify: true
            //         },
            //         compress: true
            //     }))
            //     .pipe(confusionGulp())
            //     .pipe(uglify())
            //     .pipe(gulp.dest(bundle.asset.js));

            gulp.src([
                './asset/js/app.js',
                './asset/js/page/**/*.js'
            ])
                .pipe(concat('app.js'))
                .pipe(uglify({
                    mangle: true,
                    output: {
                        beautify: true
                    },
                    compress: true
                }))
                .pipe(confusionGulp())
                .pipe(uglify())
                .pipe(gulp.dest(bundle.asset.js));
            gulp.src([
                asset.js,
                '!./asset/js/page/**/*.js',
                '!./asset/js/app.js',
            ])
                .pipe(uglify({
                    mangle: true,
                    output: {
                        beautify: true
                    },
                    compress: true
                }))
                .pipe(confusionGulp())
                .pipe(uglify())
                .pipe(gulp.dest(bundle.asset.js));
        }
    }
});
gulp.task('clean-js', function () {
    return gulp.src(['./public/static/js'], {read: false}).pipe(clean());
});

// 组件（bootstrap、swiper等）
gulp.task('component', function() {
    if (SceneVariable == bundle.env.dev) {
        gulp.src(asset.component).pipe(gulp.dest(bundle.asset.component));
    } else {        
        if (bundle.revision) {
            gulp.src(asset.component).pipe(rev()).pipe(gulp.dest(bundle.asset.component))
                .pipe(rev.manifest()).pipe(gulp.dest(bundle.revPath + '/component'));
        } else {
            gulp.src(asset.component).pipe(gulp.dest(bundle.asset.component));
        }
    }
});
gulp.task('clean-component', function () {
    return gulp.src(['./public/static/component'], {read: false}).pipe(clean());
});

// 模板文件，仅压缩；
gulp.task('template', function() {
    if (SceneVariable == bundle.env.dev) {
        gulp.src(asset.template.frontend)
            .pipe(gulp.dest(bundle.asset.template.frontend));
        gulp.src(asset.template.backend)
            .pipe(gulp.dest(bundle.asset.template.backend));
    } else {        
        gulp.src(asset.template.frontend)
            .pipe(gulpif(
                true, htmlmin({
                    empty: true,
                    spare: true,
                    quotes: true
                })
            ))
            .pipe(gulp.dest(bundle.asset.template.frontend));
        gulp.src(asset.template.backend)
            .pipe(gulpif(
                true, htmlmin({
                    empty: true,
                    spare: true,
                    quotes: true
                })
            ))
            .pipe(gulp.dest(bundle.asset.template.backend));
    }
});
gulp.task('clean-template', function () {
    return gulp.src([
        bundle.asset.template.frontend,
        bundle.asset.template.backend
    ], {read: false}).pipe(clean());
});

// 添加 hash，特别是 html、css 中的那些静态资源；
gulp.task('rev', function () {
    // 这些被排除的，是因为前面已经加过 hash 了；
    // gulp.src([asset.revPath + '**/*.json', './public/**/*', '!./public/image/**/*',
    //     '!./public/font/**/*.ttf',
    //     '!./public/font/**/*.eot',
    //     '!./public/font/**/*.woff',
    //     '!./public/font/**/*.svg'
    // ])
    //     .pipe(revCollector())
    //     .pipe(gulp.dest('./public'));

    // gulp.src(['./pages/**/*'])
    //     .pipe(revCollector())
    //     .pipe(gulp.dest('./pages'));

    // 统一
    gulp.src([bundle.revPath + '/**/*.json',
        './public/static/**/*',
        '!./public/static/image/**/*',
        '!./public/static/font/**/*.ttf',
        '!./public/static/font/**/*.eot',
        '!./public/static/font/**/*.woff',
        '!./public/static/font/**/*.svg',
        '!./public/static/.gitignore'
    ])
        .pipe(revCollector())
        .pipe(gulp.dest('./public/static'));

// console.log('rev............................');
    // 各自分开
    // 成功。当然，dest 那里必须 './public/static/css'。
    // gulp.src([bundle.revPath + '/image/rev-manifest.json', './public/static/css/*.css'])
    // // gulp.src([bundle.revPath + '/**/*.json', './public/static/css/*.css'])
    //     .pipe(revCollector({
    //         replaceReved: true,//允许替换, 已经被替换过的文件
    //         // dirReplacements: {
    //         //     'css': '/dist/css',
    //         //     'js': '/dist/js'
    //         // }
    //     }))
    //     .pipe(gulp.dest('./public/static/css'));
    // gulp.src([bundle.revPath + '/image/rev-manifest.json',
    //     './public/static/css/*.css',
    // ])
    //     .pipe(revCollector())
    //     .pipe(gulp.dest('./public/static/css'));
    // gulp.src([bundle.revPath + '/image/rev-manifest.json',
    //     './public/static/css/*.css',
    // ])
    //     .pipe(revCollector())
    //     .pipe(gulp.dest('./public/static/css'));

    // 经过下面这个测试，确定 src 里都是文件。
    // 之前写的是 bundle.asset.template.frontend，这是一个目录，是错误的，即使不指定扩展名，也应该加上 /**/* 才对。
    // gulp.src([bundle.revPath + '/**/*.json', bundle.asset.template.frontend])
    gulp.src([bundle.revPath + '/**/*.json', bundle.asset.template.frontend + '/**/*.html'])
        .pipe(revCollector())
        .pipe(gulp.dest(bundle.asset.template.frontend));
    
    // gulp.src(asset.template.backend)
    //     .pipe(revCollector())
    //     .pipe(gulp.dest(bundle.asset.template.backend));
});
gulp.task('clean-rev', function () {
    return gulp.src([bundle.revPath], {read: false}).pipe(clean());
});

// 删除目录和文件；
gulp.task('clean', function (done) {
    // return gulp.src([
    //     bundle.asset.template.frontend,
    //     bundle.asset.template.backend,
    //     './public/static/**/*',
    //     '!./public/static/upload/**/*',
    //     '!./public/static/.gitignore'
    // ], {read: false}).pipe(clean());
    runSequence(
        ['clean-image', 'clean-font', 'clean-scss', 'clean-js', 'clean-component', 'clean-template', 'clean-rev'],
        done);
});

// 清理 hash；
// gulp.task('cleanRev', function () {
//     return gulp.src(asset.revPath, {read:false})
//         .pipe(clean());
// });

gulp.task('watch', function() {
    // gulp.watch(asset.audio, ['audio']);
    gulp.watch(asset.js, ['js']);
    gulp.watch(asset.scss, ['scss']);
    gulp.watch(asset.font, ['font']);
    gulp.watch(asset.image, ['image']);
    gulp.watch(asset.component, ['component']);
    // gulp.watch(asset.componentHtml, ['component']);
    // gulp.watch(asset.componentJs, ['component']);
    // gulp.watch(asset.componentScss, ['component']);
    gulp.watch(asset.template.frontend, ['template']);
    // gulp.watch(asset.template.backend, ['template']);
});

// 开发构建
gulp.task('development', function (done) {
    runSequence(
        ['clean'],
        ['image', 'font', 'scss', 'js', 'component', 'template'],
        ['watch'],
        done);
});

// 生产构建
gulp.task('production', function (done) {
    SceneVariable = 'production';
    bundle.revision = true;
    runSequence(
        ['clean'],
        ['image', 'font', 'scss', 'js', 'component', 'template'],//
        // ['rev'],// 未知原因，无法在这里成功的给css、html文件内容替换静态资源名称；
        // 目前的方法是：先执行 gulp production，而后单独执行 gulp rev。
        done);
});

gulp.task('default',function(){
    gulp.start('development');
});


// 根据环境变量自动构建
// gulp.task('accord', function (done) {
//     if(SceneVariable=='development'){
//         runSequence(
//             ['clean'],
//             ['wxVerify','audio', 'images', 'font', 'scss', 'component', 'js', 'pages'],
//             ['watch'],
//             done);
//     }else{
//         runSequence(
//             ['clean'],
//             ['wxVerify','audio', 'images', 'font', 'scss', 'component', 'js', 'pages'],
//             ['Rev'],
//             done);
//     }
// });

// 测试构建
// 但是由于每个任务内只有 development 和 production 的区别，所以暂时不要 test 了。
// gulp.task('test', function (done) {
//     SceneVariable = 'test';
//     runSequence(
//         ['clean'],
//         ['wxVerify','audio', 'images', 'font', 'scss', 'component', 'js', 'pages'],
//         ['Rev'],
//         done);
// });